home *** CD-ROM | disk | FTP | other *** search
/ TPUG - Toronto PET Users Group / TPUG Users Group CD / TPUG Users Group CD.iso / AMIGA / AMICUS / AMIBEST1.ADF / AmigaBasicStuff / BasicGadgets / Gadgets.DOC < prev    next >
Text File  |  1986-11-06  |  20KB  |  485 lines

  1.  
  2.  
  3.  
  4.  
  5.                                            Catley,Basic Gadgets,Page 1 
  6.  
  7.  
  8.      As I'm sure you're aware, gadgets are those little boxes 
  9. containing a word or two, or some type of symbol, which appear in 
  10. windows and invite you to click on them to cause some predetermined 
  11. event to occur.  Unfortunately, Amiga Basic contains no built-in 
  12. functions for drawing or checking gadgets.  However, it is a 
  13. relatively easy task to draw and check your own gadgets, and that's 
  14. what we're going to look at!  Not only will we see how to do it, but 
  15. we'll also see how to do all this from three subprograms that may be 
  16. merged into any program which requires them.  You will, in effect, 
  17. create your own gadget functions! 
  18.  
  19. A Simple Gadget 
  20.      The simplest form of gadget is just a box with a word in it.  For 
  21. example: 
  22.  
  23.      CLS:LINE (36,20)-(92,36),1,b:LOCATE 4,6:PRINT "Gadget" 
  24.  
  25.      From a purely functional point of view, there is nothing wrong 
  26. with this gadget, but you will probably prefer one that is a little 
  27. more pleasing to the eye.  However, there is an important lesson to be 
  28. learned from this simple gadget!  Choosing the gadget coordinates! 
  29.      The first thing to do is to decide on the location of the text 
  30. which will appear within the gadget, and then choose the appropriate 
  31. coordinates for the box itself.  In the example above, the box is 
  32. drawn four pixels, or half a character wider and higher than the text 
  33. itself.  You may, of course, draw your box any distance from the text 
  34. you decide, but if it is too big it will look a little odd!  The most 
  35. important thing to remember is that text is, for the most part, drawn 
  36. at a specific row and column location, and the box should surround the 
  37. text evenly. 
  38.  
  39. A Prettier Gadget 
  40.      Okay, let's see what we can do to make this gadget a little nicer 
  41. to look at; something we'd like to have in our programs!  How about if 
  42. we make the box solid and then outline it with a contrasting color? 
  43. While we're at it, let's insert an inner outline, and place a "shadow" 
  44. on the right and lower sides!  Try the following program to see what 
  45. it looks like: 
  46.  
  47.      LINE (36,20)-(92,36),1,bf 
  48.      LINE (36,20)-(92,36),3,b 
  49.      LINE (38,22)-(90,34),3,b 
  50.      LINE (93,21)-(93,37),2 
  51.      LINE (93,37)-(37,37),2 
  52.      COLOR 3:LOCATE 4,6:PRINT "Gadget" 
  53.  
  54.      If more than one gadget is present at the same time, we can even 
  55. use different colors; how about green for a "Yes" gadget, and red for 
  56. a "No" gadget? 
  57.      Please note that the rest of our discussion will be based on 
  58.  
  59.  
  60.  
  61.  
  62.  
  63.  
  64.  
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.                                            Catley,Basic Gadgets,Page 2 
  72.  
  73.  
  74. gadgets of the "prettier type" described above.  Feel free to 
  75. establish your own design, but it will also become necessary for you 
  76. to make the appropriate changes through-out the remainder of our 
  77. discussion! 
  78.  
  79. The Components of a Gadget 
  80.      By now it should be pretty obvious that to draw each gadget 
  81. separately, using the code shown above, would be very cumbersome and a 
  82. very poor approach.  This is the perfect situation in which to use a 
  83. subroutine.  But we're going one step further, and use a subprogram! 
  84. The two big reasons for this are that subprograms are a lot more 
  85. independent (very important when they will be used in many programs), 
  86. and they can be used in a similar fashion to other functions, i.e. 
  87. "name parameters"; and this makes the program easier to read and less 
  88. complicated. 
  89.      Now, what information about each gadget is our subprogram, (let's 
  90. name it "DrawGdgts"), going to need?  Well, for starters, it will need 
  91. the coordinates of the upper left-hand corner and either the length 
  92. and height in pixels, or the coordinates of the lower right-hand 
  93. corner.  We'll use the former, it's easier!  Also, we're going to need 
  94. the color of the gadget's background, the color of the border and 
  95. contents, the color of the "shadow", and finally, the text that is to 
  96. be inserted in the gadget.  That's eight different pieces of 
  97. information! 
  98.      The most obvious way of handling this is to pass all eight pieces 
  99. of information to "DrawGdgts" each time we want to draw a gadget. 
  100. Using our earlier example, we'd have: 
  101.  
  102.      DrawGdgts 36,20,56,16,1,3,2,"Gadget" 
  103.  
  104.      While there is nothing particularly bad about this approach, its 
  105. biggest disadvantage is that each gadget must be drawn individually; 
  106. we cannot specify a range of gadgets to draw. 
  107. This is not terribly important when drawing gadgets (unless you have a 
  108. lot of them on the screen at once), but it does take on some 
  109. significance when checking which gadget has been selected.  Thus, it 
  110. becomes important to be able to specify a range of gadgets to be drawn 
  111. or checked - which is why we called the subprogram "DrawGdgts" rather 
  112. than "DrawGdgt"! 
  113.      Needless to say, given this requirement, the information about 
  114. the gadgets must be stored in an array; and since we have both numeric 
  115. and string data, we'll actually need two arrays.  This automatically 
  116. means the need to DIMension two arrays, and to provide a series of 
  117. DATA statements which describe the gadgets. 
  118.      This might be done as follows: 
  119.  
  120.      NumGdgts=4:DIM Gdgts(NumGdgts-1,6),GdgtTxt$(NumGdgts-1) 
  121.  
  122.      The following points are of interest: 
  123.  
  124.  
  125.  
  126.  
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134.  
  135.  
  136.  
  137.                                            Catley,Basic Gadgets,Page 3 
  138.  
  139.  
  140.      -A variable (NumGdgts) is used to specify the actual number of 
  141.       gadgets that will be used.  As we add or delete gadgets to our 
  142.       programs, we only have to change the value of one variable 
  143.       rather than searching through the entire program for every 
  144.       reference to the number of gadgets. 
  145.  
  146.      -The "Gdgts" array is two-dimensional; one seven position entry 
  147.       for each gadget. 
  148.  
  149.      -Remember that arrays start at entry zero, so they are 
  150.       dimensioned to the maximum number less one. 
  151.  
  152.      The associated DATA statements would look something like: 
  153.  
  154.      DATA 36, 20, 56, 16, 1, 3, 2, "Gadget" 
  155.  
  156.      In other words, it contains the same eight pieces of information 
  157. we've already been discussing!  One important point must be made here, 
  158. just in case it has not become obvious!  Since we will be drawing and 
  159. checking our gadgets in ranges, gadgets that will appear on the screen 
  160. at the same time, must be grouped together in the DATA statements. 
  161.  
  162. Saving the Gadget's Components 
  163.      All of this brings us to the first of our three subprograms,  
  164. creating the arrays from the DATA statements.  Let's call this 
  165. subprogram "BldGdgts".  Now, what information is "BldGdgts" going to 
  166. need to perform its defined function of building the two gadget 
  167. arrays?  Well, it's going to need to know the total number of gadgets, 
  168. and the names of the two arrays.  We'll pass all three pieces of 
  169. information as parameters; we could use the SHARED statement, but 
  170. while we'll remove the need for parameters, we would be forced into 
  171. using the same names in every program, and that might not be what we 
  172. really want.  So, we'll invoke our "BldGdgts" subprogram with one of 
  173. two statements types: 
  174.  
  175.      CALL BldGdgts (NumGdgts,Gdgts(),GdgtTxt$()) 
  176.  
  177.      or 
  178.  
  179.      BldGdgts NumGdgts,Gdgts(),GdgTxt$ 
  180.  
  181.      Either form is correct and the choice is strictly a personal one. 
  182. Note how the arrays are specified.  The () is required for Basic to 
  183. know it is an array being passed and not a variable. 
  184.      Look at Listing #1 and then type it in.  This is our "BldGdgts" 
  185. subprogram; it is a pretty straight-forward use of the READ statement 
  186. to extract values from DATA statements and place them in arrays.  Note 
  187. that while the specified parameters must be in the same sequence, they 
  188. do not need the same names, and that variable names are unique within 
  189. a subprogram; i.e. "x" in a subprogram is a different variable from 
  190.  
  191.  
  192.  
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.  
  201.  
  202.  
  203.                                            Catley,Basic Gadgets,Page 4 
  204.  
  205.  
  206. "x" in a main program. 
  207.      Since we will eventually be combining the other two subprograms 
  208. with "BldGdgts", pick an appropriate name to save it as!  How about 
  209. "Gadgets"?  And remember to save it with the ",A" option; for example: 
  210. SAVE "Gadgets",A 
  211.      This will allow the code to be merged in with other programs at a 
  212. later time.  N.B. You must use an immediate command to do this, the 
  213. Project Save menu item cannot be used, at least not for the first 
  214. save. 
  215.  
  216. Drawing the Gadgets 
  217.      All of the array information is now stored in arrays, and the 
  218. time has come to use "DrawGdgts".  To do its job, this subprogram 
  219. needs to know the starting and ending gadgets to be drawn, and the 
  220. name of the arrays containing the gadget data.  Thus, we might use 
  221.  
  222.      CALL DrawGdgts (2,5,Gdgts(),GdgtTxt$()) 
  223.  
  224. to draw gadgets three through six from the arrays; (remember, the 
  225. first entry in an array is entry zero). 
  226.      Now, "DrawGdgts" itself will set up a loop, and for each gadget 
  227. to be drawn, it will: 
  228.  
  229.      -extract the necessary data from the array, (not strictly 
  230.       necessary, but it allows Basic to make the array calculation 
  231.       only once, and it also allows shorter, more usable names to be 
  232.       applied to the values) 
  233.  
  234.      -draw the gadget in much the same fashion as we did earlier 
  235.  
  236.      -print the text in the gadget after calculating the starting row 
  237.       and column 
  238.  
  239.      Listing #2 shows the "DrawGdgts" subprogram.  It also shows 
  240. something new!  The inner outline, text and shadow are only drawn if 
  241. the "shadow" color is greater than -1 (or is a valid palette number)! 
  242. This minor extension allows us to handle another type of gadget very 
  243. easily. 
  244.      Up to this point we've been discussing "Yes/No" type gadgets 
  245. which will "flash" when clicked on, and which are used simply to 
  246. indicate the user's choices.  Another type of gadget is used for data 
  247. entry purposes.  For example, in a requester, a user clicks in a box 
  248. to indicate some data will be entered.  The box reverses its outline 
  249. and interior colors and all is ready for some data to be entered. 
  250.      Since this type of gadget will not use a "shadow", we can use 
  251. this field to indicate the type of gadget by using an illegal palette 
  252. number.  So, if we desire this form of gadget, we set the  
  253. "shadow" color to -1 and everything will be taken care of 
  254. automatically! 
  255.      Back to "DrawGdgts"; if a -1 is detected as the shadow color, 
  256.  
  257.  
  258.  
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269.                                            Catley,Basic Gadgets,Page 5 
  270.  
  271.  
  272. then only the box and its outline are drawn.  The inner outline and 
  273. the text are ignored. 
  274.      Now, LOAD "Gadgets" (or whatever you called it) and extend it by 
  275. adding Listing #2 to the end, and then save it again.  The ",A" should 
  276. not be necessary this time, and the Project Menu save  item may also 
  277. be used.  Once saved with the ",A", all future saves (or replaces) 
  278. will automatically use the ASCII format. 
  279.  
  280. Which Gadget was Clicked? 
  281.      Our third subprogram, "GetGdgt" is also our most complicated!  So 
  282. before looking at how it works, let's review how  
  283. the mouse might be used to check for a simple gadget being clicked. 
  284. Remember, MOUSE(0) returns a zero value until the left button is 
  285. pressed when MOUSE(1) returns the x coordinate of the mouse pointer, 
  286. and MOUSE(2) returns the y coordinate.  The following sample program 
  287. draws a simple gadget, and will not quit       
  288. until you click in the gadget.  Try it! 
  289.  
  290.      LINE (36,28)-(92,42),1,B    'Draw Gadget 
  291.      LOCATE 5,7:PRINT"Quit"      'Insert Text  
  292.      Ok=0                        'Set Flag=0 
  293.      WHILE Ok=0                  'Loop till flag not zero 
  294.        WHILE MOUSE(0)=0:WEND     'Wait for click 
  295.        x=MOUSE(1):y=MOUSE(2)     'Pick up x & y coordinates 
  296.        IF x>36 AND x<92 THEN     'Check x coordinates  
  297.          IF y>28 AND Y<42 THEN   'Check y coordinates 
  298.            Ok=1                  'Set flag=1 if in gadget 
  299.          END IF 
  300.        END IF 
  301.      WEND 
  302.      LOCATE 1,1:PRINT"You did it!" 
  303.      END 
  304.  
  305.      The above is pretty straight forward, and once you understand it, 
  306. "GetGdgt" will be that much easier to follow. 
  307.      To do its job, "GetGdgt" (Listing #3) needs to know the range of 
  308. gadgets to be checked, the names of the gadget arrays, and to have a 
  309. means of letting the caller know which gadget was clicked in.  The 
  310. latter may be handled with a variable that is set to the relative 
  311. number of the gadget clicked in, within the given range.  This being 
  312. the case, 
  313.  
  314.      CALL GetGdgt (2,5,Gdgts(),GdgtTxt$(),gdgt) 
  315.  
  316. may be used to determine which gadget, if any, has been clicked.  In 
  317. this example, "gdgt" will return 0-4 depending on whether the click 
  318. was outside all the gadgets, or was in one of gadgets 3, 4, 5, or 6 
  319. respectively.  If "gdgt" comes back as zero, we'll almost certainly 
  320. want to loop back and issue the call again.  The following is an 
  321. example of how "GetGdgt" might actually be used in many situations: 
  322.  
  323.  
  324.  
  325.  
  326.  
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335.                                            Catley,Basic Gadgets,Page 6 
  336.  
  337.  
  338.  
  339.      gdgt=0 
  340.      WHILE gdgt=0 
  341.        CALL GetGdgt (2,5,Gdgts(),GdgtTxt$(),gdgt) 
  342.      WEND 
  343.      ON gdgt GOTO Rtn3,Rtn4,Rtn5,Rtn6 
  344.  
  345.      The obvious question right now is "Why can't GetGdgt be written 
  346. to wait for a click in one of the specified gadgets?"  The answer, for 
  347. now, is "Flexibility".  We'll discuss a more practical reason later! 
  348.      Beside the five parameters, "GetGdgt" also shares three variables 
  349. with the main program.  All are conveniences for the main program; two 
  350. pass back the actual x and y coordinates selected, and the third is 
  351. simply an indicator that a valid gadget was, indeed, selected.  The 
  352. first two are useful when the program needs to know where the pointer 
  353. was in the gadget when it was clicked, while the third can be useful 
  354. if the program is waiting on more events than just a gadget being 
  355. selected. 
  356.      Anyway, once "GetGdgt" is called, it waits for a click, sets 
  357. variables and picks up the x and y coordinates of the pointer.  It 
  358. then loops through the specified range of gadgets to see if any of 
  359. them were clicked.  If one was, the gadget is drawn in its opposite 
  360. colors (starting the "flash"), the relative number of the gadget 
  361. within the specified range is calculated and set, and the loop is 
  362. terminated.  At this point, the subprogram waits for the left button 
  363. to be released, when it redraws the gadget in its usual colors, (if 
  364. the gadget has been selected and the shadow color is greater than -1 
  365. and thereby ending the flash).  Before returning to the main program, 
  366. the cursor is relocated to its original position.  (The need for this 
  367. last function is not that obvious, but I found it the hard way when 
  368. trying to combine user input and gadget selection!) 
  369.      The listing of "GetGdgt" may look a little complicated, but it 
  370. really isn't.  It's just the example we looked at earlier with a few 
  371. bells and whistles thrown in! 
  372.      It's now time to add "GetGdgt" to "Gadgets".  Load "Gadgets" and 
  373. extend it with Listing #3 and save the entire thing.  You could have 
  374. saved each of the three subprograms separately if you wished, but 
  375. since the chance of one being used without the other is very slim, it 
  376. makes more sense to combine them into one program unit. 
  377.  
  378. Let's Try Them Out 
  379.      After all that effort we'd better make sure they work correctly! 
  380. Listing #4 shows a sample program which exercises all three 
  381. subprograms.  Enter it as shown, and then click in the Basic Output 
  382. Window and enter the immediate command:  MERGE "Gadgets" (or whatever 
  383. you called the subprograms). 
  384.      The three subprograms should be appended to Listing #4 in your 
  385. Edit Window.  If you receive a "Bad File Mode" error message you 
  386. probably forgot to use the ",A" option when you originally saved 
  387. "BldGdgts".  No problem!  Just save Listing #4, load "Gadgets" again 
  388.  
  389.  
  390.  
  391.  
  392.  
  393.  
  394.  
  395.  
  396.  
  397.  
  398.  
  399.  
  400.  
  401.                                            Catley,Basic Gadgets,Page 7 
  402.  
  403.  
  404. and then resave it with the ",A" option; (use the immediate command: 
  405. SAVE "Gadgets",A), reload Listing #4 and then issue the MERGE again. 
  406. Once you have them combined, save the entire program as, say, 
  407. "GdgtDemo"; (no need to use the ",A" option now). 
  408.      If you look at Listing #4, it wont be too long before you notice 
  409. two things that are different from what we have discussed so far. 
  410. First, there is a gadget with a shadow color of -2, and we are using a 
  411. completely different method of waiting for the mouse click! 
  412.      The former is easy, it just gives us a third type of gadget 
  413. without any need to modify the gadget subprograms.  This gadget will 
  414. not change at all when it is clicked in.  A useful option when 
  415. selecting an item from a list to obtain further information in a 
  416. separate window. 
  417.      The second is a little more involved.  Rather than use the method 
  418. of checking the mouse described above, we set up a mouse event 
  419. trapping routine, (ON MOUSE GOSUB GetMouse); turn it on, (MOUSE ON); 
  420. and then, when it's time to wait for the click, we go to SLEEP until 
  421. the user clicks the button.  At this point, control automatically 
  422. passes to the "GetMouse" routine which simply invokes "GetGdgt".  The 
  423. RETURN results in control being passed back to the statement 
  424. immediately following the one that was being executed when the "mouse 
  425. event" occurred.  In our case, this is the WEND following the SLEEP. 
  426. Now, if "gdgt" is still zero, the program goes right back to SLEEP; if 
  427. it is non-zero, it responds appropriately.  In other words, we are 
  428. waiting for the click, via the SLEEP statement, outside of the 
  429. "GetGdgt" routine. 
  430.      Why is this an important option?  Well, assume you have a program 
  431. which puts up a "Yes/No" requester, and then goes to "GetGdgt" and 
  432. dutifully waits at the WHILE MOUSE(0) statement.  Meanwhile, the user 
  433. scratches his/her head and decides to use the help menu that you have 
  434. thoughtfully provided, and at the bottom of the help window, lo and 
  435. behold, is an "OK" gadget.  The result of this is that when the help 
  436. routine tries to go to "GetGdgt", the program crashes with an error 
  437. message informing you that a subprogram cannot be used by two users at 
  438. the same time! It is, therefore, important to wait outside of the 
  439. "GetGdgt" subprogram!  SLEEP is used because it does not require any 
  440. CPU cycles (unlike WHILE MOUSE(0)=0:WEND) and this is very important 
  441. in a multitasking machine such as the Amiga.  SLEEP is also useful 
  442. when you're waiting for one of several events to occur.  Just set up 
  443. the event traps and go to SLEEP; there is no need to establish a loop 
  444. which is constantly checking on all the events you are waiting on! 
  445.      All this is not to say that polling (WHILE MOUSE(0)=0:WEND) 
  446. should never be used.  Event traps are just an alternate (but probably 
  447. better) method, which involves a little more programming, but which 
  448. offers a number of advantages. 
  449.      We got side tracked, back to our "GdgtDemo" program!  Once you've 
  450. entered Listing #4, MERGEd in the "Gadgets" subprograms, and saved it; 
  451. RUN it.  The screen will show a number of gadgets examples in the 
  452. lower portion, and will have two "real" gadgets at the top, "More" and 
  453. "Quit".  If you click in any of the example gadgets, you'll receive a 
  454.  
  455.  
  456.  
  457.  
  458.  
  459.  
  460.  
  461.  
  462.  
  463.  
  464.  
  465.  
  466.  
  467.                                            Catley,Basic Gadgets,Page 8 
  468.  
  469.  
  470. message telling you which one you clicked.  If you select "More", 
  471. you'll receive a second screen of example gadgets, with "Repeat" and 
  472. "Quit" gadgets at the top.  As you might expect, "Repeat" returns you 
  473. to the first set of examples, and "Quit" terminates the program, as it 
  474. does on the first screen. 
  475.      Well, you are now an expert at creating and using your own custom 
  476. gadgets from within Amiga Basic!  Use them well and spruce up those 
  477. programs!  
  478.  
  479.    
  480.       
  481.  
  482.  
  483.          
  484.  
  485.